package com.piggy.logi.sys.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.piggy.common.core.utils.PageUtils;
import com.piggy.common.core.web.page.PagePlus;
import com.piggy.common.core.web.page.TableDataInfo;
import com.piggy.logi.sys.api.domain.LogiSysDept;
import com.piggy.logi.sys.bo.*;
import com.piggy.logi.sys.domain.*;
import com.piggy.logi.sys.service.*;
import com.piggy.logi.sys.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 财务统计Service业务层处理
 *
 * @author fengxy
 * @date 2023/10/17 21:54
 **/
@Slf4j
@Service
public class LogiCarrierStatisticsServiceImpl implements ILogiCarrierStatisticsService {

    @Resource
    private ILogiSysDeptService logiSysDeptService;

    @Resource
    private ILogiCarrierService logiCarrierService;

    @Resource
    private ILogiCarrierDriverService logiCarrierDriverService;

    @Resource
    private ILogiCarrierCarService logiCarrierCarService;

    @Resource
    private ILogiLineService logiLineService;

    @Resource
    private ILogiWaybillService logiWaybillService;

    @Resource
    private ILogiScheduleService logiScheduleService;

    @Resource
    private ILogiScheduleFeeService logiScheduleFeeService;

    @Resource
    private ILogiWaybillGoodSourceService logiWaybillGoodSourceService;

    @Override
    public TableDataInfo<LogiDeptStatisticsVo> deptStatisticsPage(LogiDeptStatisticsQueryBo bo) {
        List<LogiWaybill> completedWaybills = logiWaybillService.getCompletedWaybills(bo.getDeptId(), bo.getStartDate(), bo.getEndDate());
        PagePlus<LogiSysDept, LogiDeptStatisticsVo> result = logiSysDeptService.pageVo(PageUtils.buildPagePlus(bo, true), buildQueryWrapper(bo, completedWaybills), LogiDeptStatisticsVo.class);
        List<LogiDeptStatisticsVo> pageListVos = result.getRecordsVo();
        fillData(pageListVos, bo, completedWaybills);
        result.setRecordsVo(pageListVos);
        return PageUtils.buildDataInfo(result);
    }

    @Override
    public List<LogiDeptStatisticsVo> deptStatisticsList(LogiDeptStatisticsQueryBo bo) {
        List<LogiWaybill> completedWaybills = logiWaybillService.getCompletedWaybills(bo.getDeptId(), bo.getStartDate(), bo.getEndDate());
        List<LogiDeptStatisticsVo> result = logiSysDeptService.listVo(buildQueryWrapper(bo, completedWaybills), LogiDeptStatisticsVo.class);
        fillData(result, bo, completedWaybills);
        return result;
    }

    @Override
    public TableDataInfo<LogiCarrierStatisticsVo> carrierStatisticsPage(LogiCarrierStatisticsQueryBo bo) {
        List<LogiWaybill> completedWaybills = logiWaybillService.getCompletedWaybills(bo.getDeptId(), bo.getStartDate(), bo.getEndDate());
        List<String> scheduleNoList = completedWaybills.stream().map(LogiWaybill::getScheduleNo).distinct().collect(Collectors.toList());
        List<LogiSchedule> scheduleList = logiScheduleService.list(Wrappers.lambdaQuery(LogiSchedule.class).in(LogiSchedule::getScheduleNo, CollUtil.isEmpty(scheduleNoList) ? CollUtil.newArrayList("") : scheduleNoList));
        PagePlus<LogiCarrier, LogiCarrierStatisticsVo> result = logiCarrierService.pageVo(PageUtils.buildPagePlus(bo, true), buildQueryWrapper(bo, scheduleList), LogiCarrierStatisticsVo.class);
        List<LogiCarrierStatisticsVo> pageListVos = result.getRecordsVo();
        fillData(pageListVos, bo, completedWaybills, scheduleList);
        result.setRecordsVo(pageListVos);
        return PageUtils.buildDataInfo(result);
    }

    @Override
    public List<LogiCarrierStatisticsVo> carrierStatisticsList(LogiCarrierStatisticsQueryBo bo) {
        List<LogiWaybill> completedWaybills = logiWaybillService.getCompletedWaybills(bo.getDeptId(), bo.getStartDate(), bo.getEndDate());
        List<String> scheduleNoList = completedWaybills.stream().map(LogiWaybill::getScheduleNo).distinct().collect(Collectors.toList());
        List<LogiSchedule> scheduleList = logiScheduleService.list(Wrappers.lambdaQuery(LogiSchedule.class).in(LogiSchedule::getScheduleNo, CollUtil.isEmpty(scheduleNoList) ? CollUtil.newArrayList("") : scheduleNoList));
        List<LogiCarrierStatisticsVo> result = logiCarrierService.listVo(buildQueryWrapper(bo, scheduleList), LogiCarrierStatisticsVo.class);
        fillData(result, bo, completedWaybills, scheduleList);
        return result;
    }

    @Override
    public TableDataInfo<LogiDriverStatisticsVo> driverStatisticsPage(LogiDriverStatisticsQueryBo bo) {
        List<LogiWaybill> completedWaybills = logiWaybillService.getCompletedWaybills(bo.getDeptId(), bo.getStartDate(), bo.getEndDate());
        List<String> scheduleNoList = completedWaybills.stream().map(LogiWaybill::getScheduleNo).distinct().collect(Collectors.toList());
        List<LogiSchedule> scheduleList = logiScheduleService.list(Wrappers.lambdaQuery(LogiSchedule.class).in(LogiSchedule::getScheduleNo, CollUtil.isEmpty(scheduleNoList) ? CollUtil.newArrayList("") : scheduleNoList));
        PagePlus<LogiCarrierDriver, LogiDriverStatisticsVo> result = logiCarrierDriverService.pageVo(PageUtils.buildPagePlus(bo, true), buildQueryWrapper(bo, scheduleList), LogiDriverStatisticsVo.class);
        List<LogiDriverStatisticsVo> pageListVos = result.getRecordsVo();
        fillData(pageListVos, bo, completedWaybills, scheduleList);
        result.setRecordsVo(pageListVos);
        return PageUtils.buildDataInfo(result);
    }

    @Override
    public List<LogiDriverStatisticsVo> driverStatisticsList(LogiDriverStatisticsQueryBo bo) {
        List<LogiWaybill> completedWaybills = logiWaybillService.getCompletedWaybills(bo.getDeptId(), bo.getStartDate(), bo.getEndDate());
        List<String> scheduleNoList = completedWaybills.stream().map(LogiWaybill::getScheduleNo).distinct().collect(Collectors.toList());
        List<LogiSchedule> scheduleList = logiScheduleService.list(Wrappers.lambdaQuery(LogiSchedule.class).in(LogiSchedule::getScheduleNo, CollUtil.isEmpty(scheduleNoList) ? CollUtil.newArrayList("") : scheduleNoList));
        List<LogiDriverStatisticsVo> result = logiCarrierDriverService.listVo(buildQueryWrapper(bo, scheduleList), LogiDriverStatisticsVo.class);
        fillData(result, bo, completedWaybills, scheduleList);
        return result;
    }

    @Override
    public TableDataInfo<LogiCarStatisticsVo> carStatisticsPage(LogiCarStatisticsQueryBo bo) {
        List<LogiWaybill> completedWaybills = logiWaybillService.getCompletedWaybills(bo.getDeptId(), bo.getStartDate(), bo.getEndDate());
        List<String> scheduleNoList = completedWaybills.stream().map(LogiWaybill::getScheduleNo).distinct().collect(Collectors.toList());
        List<LogiSchedule> scheduleList = logiScheduleService.list(Wrappers.lambdaQuery(LogiSchedule.class).in(LogiSchedule::getScheduleNo, CollUtil.isEmpty(scheduleNoList) ? CollUtil.newArrayList("") : scheduleNoList));
        PagePlus<LogiCarrierCar, LogiCarStatisticsVo> result = logiCarrierCarService.pageVo(PageUtils.buildPagePlus(bo, true), buildQueryWrapper(bo, scheduleList), LogiCarStatisticsVo.class);
        List<LogiCarStatisticsVo> pageListVos = result.getRecordsVo();
        fillData(pageListVos, bo, completedWaybills, scheduleList);
        result.setRecordsVo(pageListVos);
        return PageUtils.buildDataInfo(result);
    }

    @Override
    public List<LogiCarStatisticsVo> carStatisticsList(LogiCarStatisticsQueryBo bo) {
        List<LogiWaybill> completedWaybills = logiWaybillService.getCompletedWaybills(bo.getDeptId(), bo.getStartDate(), bo.getEndDate());
        List<String> scheduleNoList = completedWaybills.stream().map(LogiWaybill::getScheduleNo).distinct().collect(Collectors.toList());
        List<LogiSchedule> scheduleList = logiScheduleService.list(Wrappers.lambdaQuery(LogiSchedule.class).in(LogiSchedule::getScheduleNo, CollUtil.isEmpty(scheduleNoList) ? CollUtil.newArrayList("") : scheduleNoList));
        List<LogiCarStatisticsVo> result = logiCarrierCarService.listVo(buildQueryWrapper(bo, scheduleList), LogiCarStatisticsVo.class);
        fillData(result, bo, completedWaybills, scheduleList);
        return result;
    }

    @Override
    public TableDataInfo<LogiLineStatisticsVo> lineStatisticsPage(LogiLineStatisticsQueryBo bo) {
        List<LogiWaybill> completedWaybills = logiWaybillService.getCompletedWaybills(bo.getDeptId(), bo.getStartDate(), bo.getEndDate());
        List<String> scheduleNoList = completedWaybills.stream().map(LogiWaybill::getScheduleNo).distinct().collect(Collectors.toList());
        List<LogiSchedule> scheduleList = logiScheduleService.list(Wrappers.lambdaQuery(LogiSchedule.class).in(LogiSchedule::getScheduleNo, CollUtil.isEmpty(scheduleNoList) ? CollUtil.newArrayList("") : scheduleNoList));
        PagePlus<LogiLine, LogiLineStatisticsVo> result = logiLineService.pageVo(PageUtils.buildPagePlus(bo, true), buildQueryWrapper(bo, scheduleList), LogiLineStatisticsVo.class);
        List<LogiLineStatisticsVo> pageListVos = result.getRecordsVo();
        fillData(pageListVos, bo, completedWaybills, scheduleList);
        result.setRecordsVo(pageListVos);
        return PageUtils.buildDataInfo(result);
    }

    @Override
    public List<LogiLineStatisticsVo> lineStatisticsList(LogiLineStatisticsQueryBo bo) {
        List<LogiWaybill> completedWaybills = logiWaybillService.getCompletedWaybills(bo.getDeptId(), bo.getStartDate(), bo.getEndDate());
        List<String> scheduleNoList = completedWaybills.stream().map(LogiWaybill::getScheduleNo).distinct().collect(Collectors.toList());
        List<LogiSchedule> scheduleList = logiScheduleService.list(Wrappers.lambdaQuery(LogiSchedule.class).in(LogiSchedule::getScheduleNo, CollUtil.isEmpty(scheduleNoList) ? CollUtil.newArrayList("") : scheduleNoList));
        List<LogiLineStatisticsVo> result = logiLineService.listVo(buildQueryWrapper(bo, scheduleList), LogiLineStatisticsVo.class);
        fillData(result, bo, completedWaybills, scheduleList);
        return result;
    }

    /**
     * 组装查询条件 - 服务商统计
     **/
    private Wrapper<LogiSysDept> buildQueryWrapper(LogiDeptStatisticsQueryBo bo, List<LogiWaybill> completedWaybills) {
        if (CollUtil.isEmpty(completedWaybills)) {
            return Wrappers.lambdaQuery(LogiSysDept.class).isNull(LogiSysDept::getDeptId);
        }
        List<LogiSysDept> logiSysDepts = logiSysDeptService.listByIds(completedWaybills.stream().map(LogiWaybill::getDeptId).distinct().collect(Collectors.toList()));
        LambdaQueryWrapper<LogiSysDept> lqw = Wrappers.lambdaQuery();
        lqw.like(StrUtil.isNotBlank(bo.getDeptName()), LogiSysDept::getDeptName, bo.getDeptName());
        // 承运商id
        List<Long> deptIds = logiSysDepts.stream().map(LogiSysDept::getMainDeptId).distinct().collect(Collectors.toList());
        lqw.in(LogiSysDept::getDeptId, CollUtil.isEmpty(deptIds) ? CollUtil.newArrayList(0L) : deptIds);
        return lqw;
    }

    /**
     * 补充字段数据 - 服务商统计
     **/
    private void fillData(List<LogiDeptStatisticsVo> pageListVos, LogiDeptStatisticsQueryBo bo, List<LogiWaybill> completedWaybills) {
        pageListVos.parallelStream().forEach(a -> {
            // 获取物流服务商下所有部门id
            List<Long> deptIds = logiSysDeptService.listVo(Wrappers.lambdaQuery(LogiSysDept.class).select(LogiSysDept::getDeptId).apply("find_in_set({0}, ancestors)", a.getDeptId()), LogiDeptStatisticsVo.class)
                    .stream().map(LogiDeptStatisticsVo::getDeptId).collect(Collectors.toList());
            deptIds.add(a.getDeptId());
            // 获取物流服务商的运单
            List<LogiWaybill> logiWaybills = completedWaybills.stream().filter(w -> deptIds.contains(w.getDeptId())).collect(Collectors.toList());
            // 运单id集合
            List<Long> waybillIds = logiWaybills.stream().map(LogiWaybill::getWaybillId).collect(Collectors.toList());
            // 运单调度信息集合
            List<String> scheduleNoList = logiWaybills.stream().map(LogiWaybill::getScheduleNo).collect(Collectors.toList());
            List<LogiSchedule> logiScheduleList = logiScheduleService.list(Wrappers.lambdaQuery(LogiSchedule.class)
                    .in(LogiSchedule::getScheduleNo, CollUtil.isEmpty(scheduleNoList) ? CollUtil.newArrayList("") : scheduleNoList));
            // 调度车辆
            long carNum = logiScheduleList.stream().filter(b -> b.getCarId() > 0).distinct().count();
            a.setScheduleCarNum(Math.toIntExact(carNum));
            // 承运线路
            long carrierLine = logiScheduleList.stream().filter(b -> b.getLineId() > 0).count();
            a.setCarrierLine(Math.toIntExact(carrierLine));
            // 承运时间（h）
            long carrierTime = logiScheduleList.stream().filter(b -> ObjectUtil.isAllNotEmpty(b.getDepartTime(), b.getArriveTime())).mapToLong(b -> DateUtil.between(b.getDepartTime(), b.getArriveTime(), DateUnit.HOUR)).sum();
            a.setCarrierTime(Math.toIntExact(carrierTime));
            // 完成承运量（吨）
            List<LogiWaybillGoodSource> goodSourceList = logiWaybillGoodSourceService.getByWaybillIds(waybillIds);
            BigDecimal finishCarrierQuality = goodSourceList.stream().filter(b -> StrUtil.isNotBlank(b.getWeight())).map(b -> new BigDecimal(b.getWeight())).reduce(BigDecimal.ZERO, BigDecimal::add);
            a.setFinishCarrierQuality(finishCarrierQuality);
            // 承运运单量
            a.setCarrierWaybillNum(logiWaybills.size());
            // 交易额（万元）
            List<Long> scheduleIds = logiScheduleList.stream().map(LogiSchedule::getScheduleId).collect(Collectors.toList());
            List<LogiScheduleFee> logiScheduleFeeList = logiScheduleFeeService.list(Wrappers.lambdaQuery(LogiScheduleFee.class)
                    .in(LogiScheduleFee::getScheduleId, CollUtil.isEmpty(scheduleIds) ? CollUtil.newArrayList(0L) : scheduleIds));
            BigDecimal tradeAmount = logiScheduleFeeList.stream().map(b -> b.getApFrt().add(b.getApOther()).subtract(b.getCodGascard())).reduce(BigDecimal.ZERO, BigDecimal::add);
            a.setTradeAmount(tradeAmount);
            // 退货的运单
            List<LogiWaybill> returnWayBillList = logiWaybills.stream().filter(b -> b.getRefund() == 1).collect(Collectors.toList());
            // 退货运单数值统计
            if (CollUtil.isNotEmpty(returnWayBillList)) {
                // 完成退货量（吨）
                List<Long> returnWaybillIds = returnWayBillList.stream().map(LogiWaybill::getWaybillId).collect(Collectors.toList());
                BigDecimal finishReturnQuality = goodSourceList.stream().filter(b -> returnWaybillIds.contains(b.getWaybillId()) && StrUtil.isNotBlank(b.getWeight())).map(b -> new BigDecimal(b.getWeight())).reduce(BigDecimal.ZERO, BigDecimal::add);
                a.setFinishReturnQuality(finishReturnQuality);
                // 退货运单量
                a.setReturnWaybillNum(returnWayBillList.size());
                // 退货交易金额（万元）
                List<String> returnScheduleNoList = returnWayBillList.stream().map(LogiWaybill::getScheduleNo).collect(Collectors.toList());
                List<Long> scheduleIdList = logiScheduleList.stream().filter(b -> returnScheduleNoList.contains(b.getScheduleNo())).map(LogiSchedule::getScheduleId).collect(Collectors.toList());
                BigDecimal returnTradeAmount = logiScheduleFeeList.stream().filter(b -> scheduleIdList.contains(b.getScheduleId())).map(b -> b.getApFrt().add(b.getApOther()).subtract(b.getCodGascard())).reduce(BigDecimal.ZERO, BigDecimal::add);
                a.setReturnTradeAmount(returnTradeAmount);
            }

            // 提货的运单
            Map<String, Date> pickupTimeMap = logiScheduleList.stream().filter(b -> ObjectUtil.isNotNull(b.getPickupTime())).collect(Collectors.toMap(LogiSchedule::getScheduleNo, LogiSchedule::getPickupTime));
            // 提货运单数值统计
            if (CollUtil.isNotEmpty(pickupTimeMap)) {
                Map<String, Date> shipAppointmentTimeMap = logiWaybills.stream().filter(b -> ObjectUtil.isNotNull(b.getShipAppointmentTime())).collect(Collectors.toMap(LogiWaybill::getScheduleNo, LogiWaybill::getShipAppointmentTime));
                long pickupTimeout = 0L;
                Integer pickupTimeNum = 0;
                for (String key : pickupTimeMap.keySet()) {
                    if (shipAppointmentTimeMap.containsKey(key)) {
                        // 计划提货时间
                        Date shipAppointmentTime = shipAppointmentTimeMap.get(key);
                        // 实际提货时间
                        Date pickupTime = pickupTimeMap.get(key);
                        // 如果实际提货时间 > 计划提货时间，则为超时
                        if (pickupTime.compareTo(shipAppointmentTime) > 0) {
                            pickupTimeout += DateUtil.between(shipAppointmentTime, pickupTime, DateUnit.HOUR);
                        } else {
                            pickupTimeNum++;
                        }
                    }
                }
                // 提货及时率
                a.setDeliveryTimeliness(NumberUtil.formatPercent(NumberUtil.div(pickupTimeNum, a.getCarrierWaybillNum()).doubleValue(), 2));
                // 提货超时时长（h）
                a.setDeliveryTimeout(BigDecimal.valueOf(pickupTimeout));
                // 送达的运单
                Map<String, Date> arriveTimeMap = logiScheduleList.stream().filter(b -> ObjectUtil.isNotNull(b.getArriveTime())).collect(Collectors.toMap(LogiSchedule::getScheduleNo, LogiSchedule::getArriveTime));
                // 送达运单数值统计
                if (MapUtil.isNotEmpty(arriveTimeMap)) {
                    Map<String, Date> deliveryAppointmentTimeMap = logiWaybills.stream().filter(b -> ObjectUtil.isNotNull(b.getDeliveryAppointmentTime())).collect(Collectors.toMap(LogiWaybill::getScheduleNo, LogiWaybill::getDeliveryAppointmentTime));
                    long servedTimeout = 0L;
                    Integer servedTimeNum = 0;
                    for (String key : arriveTimeMap.keySet()) {
                        if (deliveryAppointmentTimeMap.containsKey(key)) {
                            // 计划送达时间
                            Date deliveryAppointmentTime = deliveryAppointmentTimeMap.get(key);
                            // 实际送达时间
                            Date servedTime = arriveTimeMap.get(key);
                            // 如果实际送达时间 > 计划送达时间，则为超时
                            if (servedTime.compareTo(deliveryAppointmentTime) > 0) {
                                servedTimeout += DateUtil.between(deliveryAppointmentTime, servedTime, DateUnit.HOUR);
                            } else {
                                servedTimeNum++;
                            }
                        }
                    }
                    // 送达及时率
                    a.setServedTimeliness(NumberUtil.formatPercent(NumberUtil.div(servedTimeNum, a.getCarrierWaybillNum()).doubleValue(), 2));
                    // 送达超时时长（h）
                    a.setServedTimeout(BigDecimal.valueOf(servedTimeout));
                }
            }
            // 时间范围
            if (ObjectUtil.isAllNotEmpty(bo.getStartDate(), bo.getEndDate())) {
                a.setTimeFrame(DateUtil.formatDate(DateUtil.parse(bo.getStartDate())) + " - " + DateUtil.formatDate(DateUtil.parse(bo.getEndDate())));
            } else {
                a.setTimeFrame("至今");
            }
        });
    }

    /**
     * 组装查询条件 - 承运商统计
     **/
    private Wrapper<LogiCarrier> buildQueryWrapper(LogiCarrierStatisticsQueryBo bo, List<LogiSchedule> scheduleList) {
        LambdaQueryWrapper<LogiCarrier> lqw = Wrappers.lambdaQuery();
        lqw.like(StrUtil.isNotBlank(bo.getCarrierName()), LogiCarrier::getCarrierName, bo.getCarrierName());
        // 承运商id
        List<Long> carrierIds = scheduleList.stream().map(LogiSchedule::getCarrierId).collect(Collectors.toList());
        lqw.in(LogiCarrier::getCarrierId, CollUtil.isEmpty(carrierIds) ? CollUtil.newArrayList(0L) : carrierIds);
        return lqw;
    }

    /**
     * 补充字段数据 - 承运商统计
     **/
    private void fillData(List<LogiCarrierStatisticsVo> pageListVos, LogiCarrierStatisticsQueryBo bo, List<LogiWaybill> completedWaybills, List<LogiSchedule> scheduleList) {
        pageListVos.parallelStream().forEach(a -> {
            // 查询符合条件的调度单号
            List<String> scheduleNoList = scheduleList.stream().filter(b -> b.getCarrierId().equals(a.getCarrierId())).map(LogiSchedule::getScheduleNo).collect(Collectors.toList());
            // 查询符合条件已完成的运单
            List<LogiWaybill> waybillList = completedWaybills.stream().filter(b -> scheduleNoList.contains(b.getScheduleNo())).collect(Collectors.toList());
            // 运单id集合
            List<Long> waybillIds = waybillList.stream().map(LogiWaybill::getWaybillId).collect(Collectors.toList());
            // 运单调度信息集合
            List<String> scheduleNos = waybillList.stream().map(LogiWaybill::getScheduleNo).collect(Collectors.toList());
            List<LogiSchedule> logiScheduleList = logiScheduleService.list(Wrappers.lambdaQuery(LogiSchedule.class).eq(LogiSchedule::getCarrierId, a.getCarrierId())
                    .in(LogiSchedule::getScheduleNo, CollUtil.isEmpty(scheduleNos) ? CollUtil.newArrayList("") : scheduleNos));
            // 调度车辆
            long carNum = logiScheduleList.stream().filter(b -> b.getCarId() > 0).distinct().count();
            a.setScheduleCarNum(Math.toIntExact(carNum));
            // 承运线路
            long carrierLine = logiScheduleList.stream().filter(b -> b.getLineId() > 0).count();
            a.setCarrierLine(Math.toIntExact(carrierLine));
            // 承运时间（h）
            long carrierTime = logiScheduleList.stream().filter(b -> ObjectUtil.isAllNotEmpty(b.getDepartTime(), b.getArriveTime())).mapToLong(b -> DateUtil.between(b.getDepartTime(), b.getArriveTime(), DateUnit.HOUR)).sum();
            a.setCarrierTime(Math.toIntExact(carrierTime));
            // 完成承运量（吨）
            List<LogiWaybillGoodSource> goodSourceList = logiWaybillGoodSourceService.getByWaybillIds(waybillIds);
            BigDecimal finishCarrierQuality = goodSourceList.stream().filter(b -> StrUtil.isNotBlank(b.getWeight())).map(b -> new BigDecimal(b.getWeight())).reduce(BigDecimal.ZERO, BigDecimal::add);
            a.setFinishCarrierQuality(finishCarrierQuality);
            // 承运运单量
            a.setCarrierWaybillNum(waybillList.size());
            // 交易额（万元）
            List<Long> scheduleIds = logiScheduleList.stream().map(LogiSchedule::getScheduleId).collect(Collectors.toList());
            List<LogiScheduleFee> logiScheduleFeeList = logiScheduleFeeService.list(Wrappers.lambdaQuery(LogiScheduleFee.class)
                    .in(LogiScheduleFee::getScheduleId, CollUtil.isEmpty(scheduleIds) ? CollUtil.newArrayList(0L) : scheduleIds));
            BigDecimal tradeAmount = logiScheduleFeeList.stream().map(b -> b.getApFrt().add(b.getApOther()).subtract(b.getCodGascard())).reduce(BigDecimal.ZERO, BigDecimal::add);
            a.setTradeAmount(tradeAmount);
            // 退货的运单
            List<LogiWaybill> returnWayBillList = waybillList.stream().filter(b -> b.getRefund() == 1).collect(Collectors.toList());
            // 退货运单数值统计
            if (CollUtil.isNotEmpty(returnWayBillList)) {
                // 完成退货量（吨）
                List<Long> returnWaybillIds = returnWayBillList.stream().map(LogiWaybill::getWaybillId).collect(Collectors.toList());
                BigDecimal finishReturnQuality = goodSourceList.stream().filter(b -> returnWaybillIds.contains(b.getWaybillId()) && StrUtil.isNotBlank(b.getWeight())).map(b -> new BigDecimal(b.getWeight())).reduce(BigDecimal.ZERO, BigDecimal::add);
                a.setFinishReturnQuality(finishReturnQuality);
                // 退货运单量
                a.setReturnWaybillNum(returnWayBillList.size());
                // 退货交易金额（万元）
                List<String> returnScheduleNoList = returnWayBillList.stream().map(LogiWaybill::getScheduleNo).collect(Collectors.toList());
                List<Long> scheduleIdList = logiScheduleList.stream().filter(b -> returnScheduleNoList.contains(b.getScheduleNo())).map(LogiSchedule::getScheduleId).collect(Collectors.toList());
                BigDecimal returnTradeAmount = logiScheduleFeeList.stream().filter(b -> scheduleIdList.contains(b.getScheduleId())).map(b -> b.getApFrt().add(b.getApOther()).subtract(b.getCodGascard())).reduce(BigDecimal.ZERO, BigDecimal::add);
                a.setReturnTradeAmount(returnTradeAmount);
            }

            // 提货的运单
            Map<String, Date> pickupTimeMap = logiScheduleList.stream().filter(b -> ObjectUtil.isNotNull(b.getPickupTime())).collect(Collectors.toMap(LogiSchedule::getScheduleNo, LogiSchedule::getPickupTime));
            // 提货运单数值统计
            if (CollUtil.isNotEmpty(pickupTimeMap)) {
                Map<String, Date> shipAppointmentTimeMap = waybillList.stream().filter(b -> ObjectUtil.isNotNull(b.getShipAppointmentTime())).collect(Collectors.toMap(LogiWaybill::getScheduleNo, LogiWaybill::getShipAppointmentTime));
                long pickupTimeout = 0L;
                Integer pickupTimeNum = 0;
                for (String key : pickupTimeMap.keySet()) {
                    if (shipAppointmentTimeMap.containsKey(key)) {
                        // 计划提货时间
                        Date shipAppointmentTime = shipAppointmentTimeMap.get(key);
                        // 实际提货时间
                        Date pickupTime = pickupTimeMap.get(key);
                        // 如果实际提货时间 > 计划提货时间，则为超时
                        if (pickupTime.compareTo(shipAppointmentTime) > 0) {
                            pickupTimeout += DateUtil.between(shipAppointmentTime, pickupTime, DateUnit.HOUR);
                        } else {
                            pickupTimeNum++;
                        }
                    }
                }
                // 提货及时率
                a.setDeliveryTimeliness(NumberUtil.formatPercent(NumberUtil.div(pickupTimeNum, a.getCarrierWaybillNum()).doubleValue(), 2));
                // 提货超时时长（h）
                a.setDeliveryTimeout(BigDecimal.valueOf(pickupTimeout));
                // 送达的运单
                Map<String, Date> arriveTimeMap = logiScheduleList.stream().filter(b -> ObjectUtil.isNotNull(b.getArriveTime())).collect(Collectors.toMap(LogiSchedule::getScheduleNo, LogiSchedule::getArriveTime));
                // 送达运单数值统计
                if (MapUtil.isNotEmpty(arriveTimeMap)) {
                    Map<String, Date> deliveryAppointmentTimeMap = waybillList.stream().filter(b -> ObjectUtil.isNotNull(b.getDeliveryAppointmentTime())).collect(Collectors.toMap(LogiWaybill::getScheduleNo, LogiWaybill::getDeliveryAppointmentTime));
                    long servedTimeout = 0L;
                    Integer servedTimeNum = 0;
                    for (String key : arriveTimeMap.keySet()) {
                        if (deliveryAppointmentTimeMap.containsKey(key)) {
                            // 计划送达时间
                            Date deliveryAppointmentTime = deliveryAppointmentTimeMap.get(key);
                            // 实际送达时间
                            Date servedTime = arriveTimeMap.get(key);
                            // 如果实际送达时间 > 计划送达时间，则为超时
                            if (servedTime.compareTo(deliveryAppointmentTime) > 0) {
                                servedTimeout += DateUtil.between(deliveryAppointmentTime, servedTime, DateUnit.HOUR);
                            } else {
                                servedTimeNum++;
                            }
                        }
                    }
                    // 送达及时率
                    a.setServedTimeliness(NumberUtil.formatPercent(NumberUtil.div(servedTimeNum, a.getCarrierWaybillNum()).doubleValue(), 2));
                    // 送达超时时长（h）
                    a.setServedTimeout(BigDecimal.valueOf(servedTimeout));
                }
            }
            // 时间范围
            if (ObjectUtil.isAllNotEmpty(bo.getStartDate(), bo.getEndDate())) {
                a.setTimeFrame(DateUtil.formatDate(DateUtil.parse(bo.getStartDate())) + " - " + DateUtil.formatDate(DateUtil.parse(bo.getEndDate())));
            } else {
                a.setTimeFrame("至今");
            }
        });
    }

    /**
     * 组装查询条件 - 司机统计
     **/
    private Wrapper<LogiCarrierDriver> buildQueryWrapper(LogiDriverStatisticsQueryBo bo, List<LogiSchedule> scheduleList) {
        LambdaQueryWrapper<LogiCarrierDriver> lqw = Wrappers.lambdaQuery();
        lqw.eq(ObjectUtil.isNotNull(bo.getDriverId()), LogiCarrierDriver::getDriverId, bo.getDriverId());
        lqw.like(StrUtil.isNotBlank(bo.getDriverName()), LogiCarrierDriver::getDriverName, bo.getDriverName());
        lqw.eq(StrUtil.isNotBlank(bo.getDriverType()), LogiCarrierDriver::getDriverType, bo.getDriverType());
        // 司机id
        List<Long> driverIds = scheduleList.stream().map(LogiSchedule::getDriverId).collect(Collectors.toList());
        lqw.in(LogiCarrierDriver::getDriverId, CollUtil.isEmpty(driverIds) ? CollUtil.newArrayList(0L) : driverIds);
        return lqw;
    }

    /**
     * 补充字段数据 - 司机统计
     **/
    private void fillData(List<LogiDriverStatisticsVo> pageListVos, LogiDriverStatisticsQueryBo bo, List<LogiWaybill> completedWaybills, List<LogiSchedule> scheduleList) {
        pageListVos.parallelStream().forEach(a -> {
            // 年龄
            a.setAge(IdcardUtil.getAgeByIdCard(a.getIdCardNo()));
            // 查询符合条件的调度单号
            List<String> scheduleNoList = scheduleList.stream().filter(b -> b.getDriverId().equals(a.getDriverId())).map(LogiSchedule::getScheduleNo).collect(Collectors.toList());
            // 查询符合条件已完成的运单
            List<LogiWaybill> waybillList = completedWaybills.stream().filter(b -> scheduleNoList.contains(b.getScheduleNo())).collect(Collectors.toList());
            // 已完成运单数值统计
            if (CollUtil.isNotEmpty(waybillList)) {
                // 运单id集合
                List<Long> waybillIds = waybillList.stream().map(LogiWaybill::getWaybillId).collect(Collectors.toList());
                // 运单调度信息集合
                List<String> scheduleNos = waybillList.stream().map(LogiWaybill::getScheduleNo).collect(Collectors.toList());
                List<LogiSchedule> logiScheduleList = logiScheduleService.list(Wrappers.lambdaQuery(LogiSchedule.class).eq(LogiSchedule::getDriverId, a.getDriverId())
                        .in(LogiSchedule::getScheduleNo, CollUtil.isEmpty(scheduleNos) ? CollUtil.newArrayList("") : scheduleNos));
                // 承运线路
                long carrierLine = logiScheduleList.stream().filter(b -> b.getLineId() > 0).count();
                a.setCarrierLine(Math.toIntExact(carrierLine));
                // 承运时间（h）
                long carrierTime = logiScheduleList.stream().filter(b -> ObjectUtil.isAllNotEmpty(b.getDepartTime(), b.getArriveTime())).mapToLong(b -> DateUtil.between(b.getDepartTime(), b.getArriveTime(), DateUnit.HOUR)).sum();
                a.setCarrierTime(Math.toIntExact(carrierTime));
                // 完成承运量（吨）
                List<LogiWaybillGoodSource> goodSourceList = logiWaybillGoodSourceService.getByWaybillIds(waybillIds);
                BigDecimal finishCarrierQuality = goodSourceList.stream().filter(b -> StrUtil.isNotBlank(b.getWeight())).map(b -> new BigDecimal(b.getWeight())).reduce(BigDecimal.ZERO, BigDecimal::add);
                a.setFinishCarrierQuality(finishCarrierQuality);
                // 交易额（万元）
                List<Long> scheduleIds = logiScheduleList.stream().map(LogiSchedule::getScheduleId).collect(Collectors.toList());
                List<LogiScheduleFee> logiScheduleFeeList = logiScheduleFeeService.list(Wrappers.lambdaQuery(LogiScheduleFee.class)
                        .in(LogiScheduleFee::getScheduleId, CollUtil.isEmpty(scheduleIds) ? CollUtil.newArrayList(0L) : scheduleIds));
                BigDecimal tradeAmount = logiScheduleFeeList.stream().map(b -> b.getApFrt().add(b.getApOther()).subtract(b.getCodGascard())).reduce(BigDecimal.ZERO, BigDecimal::add);
                a.setTradeAmount(tradeAmount);
                // 承运运单量
                a.setCarrierWaybillNum(waybillList.size());
                // 退货的运单
                List<LogiWaybill> returnWayBillList = waybillList.stream().filter(b -> b.getRefund() == 1).collect(Collectors.toList());
                // 退货运单数值统计
                if (CollUtil.isNotEmpty(returnWayBillList)) {
                    // 完成退货量（吨）
                    List<Long> returnWaybillIds = returnWayBillList.stream().map(LogiWaybill::getWaybillId).collect(Collectors.toList());
                    BigDecimal finishReturnQuality = goodSourceList.stream().filter(b -> returnWaybillIds.contains(b.getWaybillId()) && StrUtil.isNotBlank(b.getWeight())).map(b -> new BigDecimal(b.getWeight())).reduce(BigDecimal.ZERO, BigDecimal::add);
                    a.setFinishReturnQuality(finishReturnQuality);
                    // 退货运单量
                    a.setReturnWaybillNum(returnWayBillList.size());
                    // 退货交易金额（万元）
                    List<String> returnScheduleNoList = returnWayBillList.stream().map(LogiWaybill::getScheduleNo).collect(Collectors.toList());
                    List<Long> scheduleIdList = logiScheduleList.stream().filter(b -> returnScheduleNoList.contains(b.getScheduleNo())).map(LogiSchedule::getScheduleId).collect(Collectors.toList());
                    BigDecimal returnTradeAmount = logiScheduleFeeList.stream().filter(b -> scheduleIdList.contains(b.getScheduleId())).map(b -> b.getApFrt().add(b.getApOther()).subtract(b.getCodGascard())).reduce(BigDecimal.ZERO, BigDecimal::add);
                    a.setReturnTradeAmount(returnTradeAmount);
                }
                // 提货的运单
                Map<String, Date> pickupTimeMap = logiScheduleList.stream().filter(b -> ObjectUtil.isNotNull(b.getPickupTime())).collect(Collectors.toMap(LogiSchedule::getScheduleNo, LogiSchedule::getPickupTime));
                // 提货运单数值统计
                if (CollUtil.isNotEmpty(pickupTimeMap)) {
                    Map<String, Date> shipAppointmentTimeMap = waybillList.stream().filter(b -> ObjectUtil.isNotNull(b.getShipAppointmentTime())).collect(Collectors.toMap(LogiWaybill::getScheduleNo, LogiWaybill::getShipAppointmentTime));
                    long pickupTimeout = 0L;
                    Integer pickupTimeNum = 0;
                    for (String key : pickupTimeMap.keySet()) {
                        if (shipAppointmentTimeMap.containsKey(key)) {
                            // 计划提货时间
                            Date shipAppointmentTime = shipAppointmentTimeMap.get(key);
                            // 实际提货时间
                            Date pickupTime = pickupTimeMap.get(key);
                            // 如果实际提货时间 > 计划提货时间，则为超时
                            if (pickupTime.compareTo(shipAppointmentTime) > 0) {
                                pickupTimeout += DateUtil.between(shipAppointmentTime, pickupTime, DateUnit.HOUR);
                            } else {
                                pickupTimeNum++;
                            }
                        }
                    }
                    // 提货及时率
                    a.setDeliveryTimeliness(NumberUtil.formatPercent(NumberUtil.div(pickupTimeNum, a.getCarrierWaybillNum()).doubleValue(), 2));
                    // 提货超时时长（h）
                    a.setDeliveryTimeout(BigDecimal.valueOf(pickupTimeout));
                }
                // 送达的运单
                Map<String, Date> arriveTimeMap = logiScheduleList.stream().filter(b -> ObjectUtil.isNotNull(b.getArriveTime())).collect(Collectors.toMap(LogiSchedule::getScheduleNo, LogiSchedule::getArriveTime));
                // 送达运单数值统计
                if (MapUtil.isNotEmpty(arriveTimeMap)) {
                    Map<String, Date> deliveryAppointmentTimeMap = waybillList.stream().filter(b -> ObjectUtil.isNotNull(b.getDeliveryAppointmentTime())).collect(Collectors.toMap(LogiWaybill::getScheduleNo, LogiWaybill::getDeliveryAppointmentTime));
                    long servedTimeout = 0L;
                    Integer servedTimeNum = 0;
                    for (String key : arriveTimeMap.keySet()) {
                        if (deliveryAppointmentTimeMap.containsKey(key)) {
                            // 计划送达时间
                            Date deliveryAppointmentTime = deliveryAppointmentTimeMap.get(key);
                            // 实际送达时间
                            Date servedTime = arriveTimeMap.get(key);
                            // 如果实际送达时间 > 计划送达时间，则为超时
                            if (servedTime.compareTo(deliveryAppointmentTime) > 0) {
                                servedTimeout += DateUtil.between(deliveryAppointmentTime, servedTime, DateUnit.HOUR);
                            } else {
                                servedTimeNum++;
                            }
                        }
                    }
                    // 送达及时率
                    a.setServedTimeliness(NumberUtil.formatPercent(NumberUtil.div(servedTimeNum, a.getCarrierWaybillNum()).doubleValue(), 2));
                    // 送达超时时长（h）
                    a.setServedTimeout(BigDecimal.valueOf(servedTimeout));
                }
            }
            // 时间范围
            if (ObjectUtil.isAllNotEmpty(bo.getStartDate(), bo.getEndDate())) {
                a.setTimeFrame(DateUtil.formatDate(DateUtil.parse(bo.getStartDate())) + " - " + DateUtil.formatDate(DateUtil.parse(bo.getEndDate())));
            } else {
                a.setTimeFrame("至今");
            }
        });
    }

    /**
     * 组装查询条件 - 车辆统计
     **/
    private Wrapper<LogiCarrierCar> buildQueryWrapper(LogiCarStatisticsQueryBo bo, List<LogiSchedule> scheduleList) {
        LambdaQueryWrapper<LogiCarrierCar> lqw = Wrappers.lambdaQuery();
        lqw.like(StrUtil.isNotBlank(bo.getLicensePlate()), LogiCarrierCar::getLicensePlate, bo.getLicensePlate());
        lqw.eq(ObjectUtil.isNotNull(bo.getCarType()), LogiCarrierCar::getCarType, bo.getCarType());
        // 车辆id
        List<Long> carIds = scheduleList.stream().map(LogiSchedule::getCarId).collect(Collectors.toList());
        lqw.in(LogiCarrierCar::getCarId, CollUtil.isEmpty(carIds) ? CollUtil.newArrayList(0L) : carIds);
        return lqw;
    }

    /**
     * 补充字段数据 - 车辆统计
     **/
    private void fillData(List<LogiCarStatisticsVo> pageListVos, LogiCarStatisticsQueryBo bo, List<LogiWaybill> completedWaybills, List<LogiSchedule> scheduleList) {
        pageListVos.parallelStream().forEach(a -> {
            // 查询符合条件的调度单号
            List<String> scheduleNoList = scheduleList.stream().filter(b -> b.getCarId().equals(a.getCarId())).map(LogiSchedule::getScheduleNo).collect(Collectors.toList());
            // 查询符合条件已完成的运单
            List<LogiWaybill> waybillList = completedWaybills.stream().filter(b -> scheduleNoList.contains(b.getScheduleNo())).collect(Collectors.toList());
            // 已完成运单数值统计
            if (CollUtil.isNotEmpty(waybillList)) {
                // 运单id集合
                List<Long> waybillIds = waybillList.stream().map(LogiWaybill::getWaybillId).collect(Collectors.toList());
                // 运单调度信息集合
                List<String> scheduleNos = waybillList.stream().map(LogiWaybill::getScheduleNo).collect(Collectors.toList());
                List<LogiSchedule> logiScheduleList = logiScheduleService.list(Wrappers.lambdaQuery(LogiSchedule.class).eq(LogiSchedule::getCarId, a.getCarId())
                        .in(LogiSchedule::getScheduleNo, CollUtil.isEmpty(scheduleNos) ? CollUtil.newArrayList("") : scheduleNos));
                // 发车车次数
                a.setCarrierNum(logiScheduleList.size());
                // 承运线路
                long carrierLine = logiScheduleList.stream().filter(b -> b.getLineId() > 0).count();
                a.setCarrierLine(Math.toIntExact(carrierLine));
                // 完成承运量（吨）
                List<LogiWaybillGoodSource> goodSourceList = logiWaybillGoodSourceService.getByWaybillIds(waybillIds);
                BigDecimal finishCarrierQuality = goodSourceList.stream().filter(b -> StrUtil.isNotBlank(b.getWeight())).map(b -> new BigDecimal(b.getWeight())).reduce(BigDecimal.ZERO, BigDecimal::add);
                a.setFinishCarrierQuality(finishCarrierQuality);
                // 完成运单量
                a.setFinishWaybillNum(waybillList.size());
                // 交易额（万元）
                List<Long> scheduleIds = logiScheduleList.stream().map(LogiSchedule::getScheduleId).collect(Collectors.toList());
                List<LogiScheduleFee> logiScheduleFeeList = logiScheduleFeeService.list(Wrappers.lambdaQuery(LogiScheduleFee.class)
                        .in(LogiScheduleFee::getScheduleId, CollUtil.isEmpty(scheduleIds) ? CollUtil.newArrayList(0L) : scheduleIds));
                BigDecimal tradeAmount = logiScheduleFeeList.stream().map(b -> b.getApFrt().add(b.getApOther()).subtract(b.getCodGascard())).reduce(BigDecimal.ZERO, BigDecimal::add);
                a.setTradeAmount(tradeAmount);
                // 送达的运单
                Map<String, Date> arriveTimeMap = logiScheduleList.stream().filter(b -> ObjectUtil.isNotNull(b.getArriveTime())).collect(Collectors.toMap(LogiSchedule::getScheduleNo, LogiSchedule::getArriveTime));
                // 送达运单数值统计
                if (MapUtil.isNotEmpty(arriveTimeMap)) {
                    Map<String, Date> deliveryAppointmentTimeMap = waybillList.stream().filter(b -> ObjectUtil.isNotNull(b.getDeliveryAppointmentTime())).collect(Collectors.toMap(LogiWaybill::getScheduleNo, LogiWaybill::getDeliveryAppointmentTime));
                    long servedTimeout = 0L;
                    Integer servedTimeNum = 0;
                    for (String key : arriveTimeMap.keySet()) {
                        if (deliveryAppointmentTimeMap.containsKey(key)) {
                            // 计划送达时间
                            Date deliveryAppointmentTime = deliveryAppointmentTimeMap.get(key);
                            // 实际送达时间
                            Date servedTime = arriveTimeMap.get(key);
                            // 如果实际送达时间 > 计划送达时间，则为超时
                            if (servedTime.compareTo(deliveryAppointmentTime) > 0) {
                                servedTimeout += DateUtil.between(deliveryAppointmentTime, servedTime, DateUnit.HOUR);
                            } else {
                                servedTimeNum++;
                            }
                        }
                    }
                    // 送达及时率
                    a.setServedTimeliness(NumberUtil.formatPercent(NumberUtil.div(servedTimeNum, a.getFinishWaybillNum()).doubleValue(), 2));
                    // 送达超时时长（h）
                    a.setServedTimeout(BigDecimal.valueOf(servedTimeout));
                }
            }
            // 时间范围
            if (ObjectUtil.isAllNotEmpty(bo.getStartDate(), bo.getEndDate())) {
                a.setTimeFrame(DateUtil.formatDate(DateUtil.parse(bo.getStartDate())) + " - " + DateUtil.formatDate(DateUtil.parse(bo.getEndDate())));
            } else {
                a.setTimeFrame("至今");
            }
        });
    }

    /**
     * 组装查询条件 - 线路统计
     **/
    private Wrapper<LogiLine> buildQueryWrapper(LogiLineStatisticsQueryBo bo, List<LogiSchedule> scheduleList) {
        LambdaQueryWrapper<LogiLine> lqw = Wrappers.lambdaQuery();
        lqw.like(StrUtil.isNotBlank(bo.getLineName()), LogiLine::getLineName, bo.getLineName());
        lqw.and(StrUtil.isNotBlank(bo.getLineDistrict()), w -> {
            List<String> lineDistrictList = StrUtil.split(bo.getLineDistrict(), ",");
            for (String lineDistrict : lineDistrictList) {
                w.or().like(LogiLine::getLineDistrict, lineDistrict);
            }
        });
        // 路线id
        List<Long> lineIds = scheduleList.stream().map(LogiSchedule::getLineId).collect(Collectors.toList());
        lqw.in(LogiLine::getLineId, CollUtil.isEmpty(lineIds) ? CollUtil.newArrayList(0L) : lineIds);
        return lqw;
    }

    /**
     * 补充字段数据 - 线路统计
     **/
    private void fillData(List<LogiLineStatisticsVo> pageListVos, LogiLineStatisticsQueryBo bo, List<LogiWaybill> completedWaybills, List<LogiSchedule> scheduleList) {
        pageListVos.parallelStream().forEach(a -> {
            // 查询符合条件的调度单号
            List<String> scheduleNoList = scheduleList.stream().filter(b -> b.getLineId().equals(a.getLineId())).map(LogiSchedule::getScheduleNo).collect(Collectors.toList());
            // 查询符合条件已完成的运单
            List<LogiWaybill> waybillList = completedWaybills.stream().filter(b -> scheduleNoList.contains(b.getScheduleNo())).collect(Collectors.toList());
            // 已完成运单数值统计
            if (CollUtil.isNotEmpty(waybillList)) {
                // 运单id集合
                List<Long> waybillIds = waybillList.stream().map(LogiWaybill::getWaybillId).collect(Collectors.toList());
                // 运单调度信息集合
                List<String> scheduleNos = waybillList.stream().map(LogiWaybill::getScheduleNo).collect(Collectors.toList());
                List<LogiSchedule> logiScheduleList = logiScheduleService.list(Wrappers.lambdaQuery(LogiSchedule.class).eq(LogiSchedule::getLineId, a.getLineId())
                        .in(LogiSchedule::getScheduleNo, CollUtil.isEmpty(scheduleNos) ? CollUtil.newArrayList("") : scheduleNos));
                // 发车车次数
                a.setCarrierNum(logiScheduleList.size());
                // 完成承运量（吨）
                List<LogiWaybillGoodSource> goodSourceList = logiWaybillGoodSourceService.getByWaybillIds(waybillIds);
                BigDecimal finishCarrierQuality = goodSourceList.stream().filter(b -> StrUtil.isNotBlank(b.getWeight())).map(b -> new BigDecimal(b.getWeight())).reduce(BigDecimal.ZERO, BigDecimal::add);
                a.setFinishCarrierQuality(finishCarrierQuality);
                // 完成运单量
                a.setFinishWaybillNum(waybillList.size());
                // 交易额（万元）
                List<Long> scheduleIds = logiScheduleList.stream().map(LogiSchedule::getScheduleId).collect(Collectors.toList());
                List<LogiScheduleFee> logiScheduleFeeList = logiScheduleFeeService.list(Wrappers.lambdaQuery(LogiScheduleFee.class)
                        .in(LogiScheduleFee::getScheduleId, CollUtil.isEmpty(scheduleIds) ? CollUtil.newArrayList(0L) : scheduleIds));
                BigDecimal tradeAmount = logiScheduleFeeList.stream().map(b -> b.getApFrt().add(b.getApOther()).subtract(b.getCodGascard())).reduce(BigDecimal.ZERO, BigDecimal::add);
                a.setTradeAmount(tradeAmount);
                // 送达的运单
                Map<String, Date> arriveTimeMap = logiScheduleList.stream().filter(b -> ObjectUtil.isNotNull(b.getArriveTime())).collect(Collectors.toMap(LogiSchedule::getScheduleNo, LogiSchedule::getArriveTime));
                // 送达运单数值统计
                if (MapUtil.isNotEmpty(arriveTimeMap)) {
                    Map<String, Date> deliveryAppointmentTimeMap = waybillList.stream().filter(b -> ObjectUtil.isNotNull(b.getDeliveryAppointmentTime())).collect(Collectors.toMap(LogiWaybill::getScheduleNo, LogiWaybill::getDeliveryAppointmentTime));
                    long servedTimeout = 0L;
                    Integer servedTimeNum = 0;
                    for (String key : arriveTimeMap.keySet()) {
                        if (deliveryAppointmentTimeMap.containsKey(key)) {
                            // 计划送达时间
                            Date deliveryAppointmentTime = deliveryAppointmentTimeMap.get(key);
                            // 实际送达时间
                            Date servedTime = arriveTimeMap.get(key);
                            // 如果实际送达时间 > 计划送达时间，则为超时
                            if (servedTime.compareTo(deliveryAppointmentTime) > 0) {
                                servedTimeout += DateUtil.between(deliveryAppointmentTime, servedTime, DateUnit.HOUR);
                            } else {
                                servedTimeNum++;
                            }
                        }
                    }
                    // 送达及时率
                    a.setServedTimeliness(NumberUtil.formatPercent(NumberUtil.div(servedTimeNum, a.getFinishWaybillNum()).doubleValue(), 2));
                    // 送达超时时长（h）
                    a.setServedTimeout(BigDecimal.valueOf(servedTimeout));
                }
            }
            // 时间范围
            if (ObjectUtil.isAllNotEmpty(bo.getStartDate(), bo.getEndDate())) {
                a.setTimeFrame(DateUtil.formatDate(DateUtil.parse(bo.getStartDate())) + " - " + DateUtil.formatDate(DateUtil.parse(bo.getEndDate())));
            } else {
                a.setTimeFrame("至今");
            }
        });
    }
}

